package com.czmh.etc.onlinepubsys.services.impl;

import com.alibaba.fastjson.JSON;
import com.czmh.etc.onlinepubsys.entity.mingchuang.CurrentContext;
import com.czmh.etc.onlinepubsys.json.JsonResult;
import com.czmh.etc.onlinepubsys.json.mingchuang.JSONResult;
import com.czmh.etc.onlinepubsys.jy.utils.*;
import com.czmh.etc.onlinepubsys.services.JyService;
import com.czmh.etc.onlinepubsys.services.mingchuang.ICurrentContextService;
import com.jiuyv.etc.etcb2bgateway.BasicReqDTO;
import com.jiuyv.etc.etcb2bgateway.MsgFormatReqDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @ClassName：JyServiceImpl
 * @Description：TODO
 * @Author： chenzj.
 * @Date：2019/10/18 11:50.
 * @Version：1.0.0
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class JyServiceImpl implements JyService {

    private static Logger logger = LoggerFactory.getLogger(JyServiceImpl.class);

    @Autowired
    private ICurrentContextService currentContextService;

    /**
     * 接入方机构号 channelID
     */
    @Value("${jy.channelId}")
    private String channelId;

    /**
     * AES密钥
     */
    @Value("${jy.AES_Secret_Key}")
    private String aesSecretKey;

    /**
     * 签名SHA256密钥
     */
    @Value("${jy.SHA256_Secret_Key}")
    private String sHA256SecretKey;

    /**
     * 服务器请求地址
     */
    @Value("${jy.serverUrl}")
    private String serverUrl;

    @Override
    public JsonResult carPreApplication(String userId, String orderNo, String vehicleNumber, String vehicleColor) {
        Map<String, Object> param = new HashMap<>();
        param.put("requestId", orderNo);
        param.put("vehicleNumber", vehicleNumber);
        param.put("vehicleColor", vehicleColor);
        ResponseValue responseValue = send("ChannelImport", "VehiclePreApplication", param);
        JsonResult result = new JsonResult();
        CurrentContext ctx = currentContextService.getByUserId(userId);
        if(null == responseValue){
            logger.info("超时二次预申请");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Map<String, Object> param1 = new HashMap<>();
            param1.put("requestId", orderNo);
            ResponseValue responseValue1 = send("ChannelImport", "QueryApplicationProgress", param1);
            JsonResult result1 = new JsonResult();
            if(null == responseValue1){
                result1.setCode(JSONResult.FAIL);
                return result1;
            }else{
                if(responseValue1.getSpecificRespDataObject() != null && responseValue1.getSpecificRespDataObject().getReqStatus().equalsIgnoreCase("0") || (ctx.getState() == 1 && responseValue.getRespCode().equalsIgnoreCase("REPEAT_APPLY"))){
                    //预申请成功后更改当前用户的订单状态
                    ctx.setState(2);
                    currentContextService.update(ctx);
                    result.setCode(JSONResult.SUCCESS);
                    result.setData(responseValue);
                    result.setMessage(responseValue.getRespMsg());
                    return result;
                }
            }
        }else{
            //预申请成功后更改当前用户的订单状态
            if(responseValue.getRespCode().equalsIgnoreCase("SUCCESS") || (ctx.getState() == 1 && responseValue.getRespCode().equalsIgnoreCase("REPEAT_APPLY"))){
                ctx.setState(2);
                currentContextService.update(ctx);
            }
            result.setCode(JSONResult.SUCCESS);
            result.setData(responseValue);
            result.setMessage(responseValue.getRespMsg());
            return result;
        }
        result.setCode(JSONResult.FAIL);
        return result;
    }

    @Override
    public JsonResult cancelCarPreApplication(String orderNo, String reason) {
        Map<String, Object> param = new HashMap<>();
        param.put("requestId", orderNo);
        param.put("reason", reason);
        ResponseValue responseValue = send("ChannelImport", "CancelVehiclePreApplication", param);
        JsonResult result = new JsonResult();
        if(null == responseValue){
            result.setCode(JSONResult.FAIL);
            return result;
        }else{
            result.setCode(JSONResult.SUCCESS);
            result.setData(responseValue);
            result.setMessage(responseValue.getRespMsg());
            return result;
        }
    }

    @Override
    public JsonResult queryApplicationStatus(String orderNo) {
        Map<String, Object> param = new HashMap<>();
        param.put("requestId", orderNo);
        ResponseValue responseValue = send("ChannelImport", "QueryApplicationProgress", param);
        JsonResult result = new JsonResult();
        if(null == responseValue){
            result.setCode(JSONResult.FAIL);
            return result;
        }else{
            result.setCode(JSONResult.SUCCESS);
            result.setData(responseValue);
            result.setMessage(responseValue.getRespMsg());
            return result;
        }
    }

    public ResponseValue send(String module, String path, Object obj) {
        //specific data 接口特定请求数据JSON串
        String data = JsonUtil.toJson(obj);
        logger.info("上海久誉接口请求数据obj：" + obj);
        //组装基础公共参数
        BasicReqDTO basicReqDTO = new BasicReqDTO()
                .setSpecificReqData(data)
                .setAccessToken(UUID.randomUUID().toString().replace("-", ""))
                .setRequestSeq(UUID.randomUUID().toString().replace("-", ""))
                .setVersion("1.0");

        String basicData = JsonUtil.toJson(basicReqDTO);
        String encryptedData = Base64.encodeBase64String(Aes256.encrypt(basicData, aesSecretKey));

        MsgFormatReqDTO reqDTO = new MsgFormatReqDTO()
                .setChannelId(channelId)
                .setEncryptAlgorithm("AES")
                .setRequest(encryptedData)
                .setSignatureMethod("SHA256")
                .setSignature(SHAUtil.getSHA256Sign(encryptedData + "&key=" + sHA256SecretKey));

        data = JsonUtil.toJson(reqDTO);

        String url = serverUrl + module + "/" + path;

        //curl
        String curl =
                "curl -X POST -H \"Content-Type: application/json\" -H \"x-label: a,b,c\" -d '" + data
                        + serverUrl + module + "/"
                        + path;
        logger.info("上海久誉接口请求数据：" + curl);
        //client
        IHttpHelper.ResponseDTO responseDTO = new OkHttpImpl().post(
                new IHttpHelper.RequestDTO().setUrl(url).setData(data)
        );
        logger.info("上海久誉接口返回数据：" + (responseDTO == null ? null : responseDTO.toString()));
        if(responseDTO != null){
            if(responseDTO.getCode() == 200){
                //判断返回数据是否被篡改，通过秘钥签名进行验证
                ResponseData responseData = JSON.parseObject(responseDTO.getData(), ResponseData.class);
                String signature = SHAUtil.getSHA256Sign(responseData.getResponse() + "&key=" + sHA256SecretKey);
                if(signature.equalsIgnoreCase(responseData.getSignature())){
                    //对返回数据中的response数据进行解密
                    String responseStr = Aes256.decrypt(Base64.decodeBase64(responseData.getResponse()), aesSecretKey);
                    ResponseValue responseValue = JSON.parseObject(responseStr, ResponseValue.class);
                    responseValue.setSpecificRespDataObject(JSON.parseObject(responseValue.getSpecificRespData(), SpecificRespDataObject.class));
                    logger.info("上海久誉接口请求数据-responseValue：" + JSON.toJSONString(responseValue));
                    return responseValue;
                }else{
                    logger.error("上海久誉接口返回数据校验失败：服务器签名-" + signature + "-响应签名-" + responseData.getSignature());
                    return null;
                }
            }else{
                return null;
            }
        }else{
            return null;
        }
    }
}
